#pragma once

#include <mutex>
#include <pthread.h>
#include <unistd.h>
#include <queue>
#define NUM 500
using namespace std;

namespace yui
{
   
    template<class T>
    class BlockQueue{
        private:
            bool isFull(){
                return _blockQueue.size() == _cap;
            }
            bool isEmpty(){
                return _blockQueue.empty();
            }
        public:
            BlockQueue(int cap = NUM):_cap(cap)
            {
                pthread_mutex_init(&_mutex,nullptr);
                pthread_cond_init(&_producer,nullptr);
                pthread_cond_init(&_consumer,nullptr);
            }
            void push(const T& inData){
                //访问公共资，加锁
                pthread_mutex_lock(&_mutex);
                //开始判断阻塞队列是否为满
                while(isFull()){
                    //如果队列为满，生产者就必须开始等待
                    // pthread_cond_signal(&_consumer);
                    pthread_cond_wait(&_producer,&_mutex);
                }
                //运行到这里队列肯定没满，将数据入队，通知消费者消费。
                _blockQueue.push(inData);
                pthread_cond_signal(&_consumer);
                pthread_mutex_unlock(&_mutex);//解锁
            }
            void pop(T* outData){
                //加锁
                pthread_mutex_lock(&_mutex);
                while(isEmpty()){
                    // pthread_cond_signal(&_producer);
                    pthread_cond_wait(&_consumer,&_mutex);
                }
                *outData = _blockQueue.front();
                _blockQueue.pop();
                pthread_cond_signal(&_producer);
                pthread_mutex_unlock(&_mutex);
            }
            ~BlockQueue()
            {
                pthread_mutex_destroy(&_mutex);
                pthread_cond_destroy(&_producer);
                pthread_cond_destroy(&_consumer);
            }
        private:
            queue<T> _blockQueue; // 阻塞队列内核
            int _cap; // 队列长度
            pthread_mutex_t _mutex; //互斥锁
            pthread_cond_t _producer; 
            pthread_cond_t _consumer;
    };
}